#include <QMessageBox>
#include <QUrl>
#include <QInputDialog>
#include <QList>
#include <QIcon>
#include <QString>
#include <QPixmap>
#include <QHideEvent>
#include <QKeyEvent>
#include <QTreeWidgetItemIterator>
#include <QTreeWidgetItem>
#include <QProgressBar>
#include <QDesktopServices>
#include <QFileDialog>
#include <QProcess>
#include <QStringList>
#include <QFont>
#include <QUrl>
#include <QStringList>

#include "formmain.h"
#include "formabout.h"
#include "formeditfeed.h"
#include "formsettings.h"
#include "formeditcategory.h"
#include "definitions.h"
#include "functions.h"
#include "rssthread.h"

#include <QStaticText>
#include <QTextItem>
FormMain::FormMain(QWidget *parent) : QMainWindow(parent), ui(new Ui::FormMain) {
    ui->setupUi(this);
    setupSettings();
    setupApp();
    setupTray();
    createConnections();
    loadSettings();
    reader->loadXml(true, reader->getPath());
    reader->updateRepresentation(ui->treeFeeds);
    emit trayNeedsRefresh();
    setMessage(tr("Welcome to RSS Guard<br><br>Current version: %1<br>You have %2 unread messages").arg(qApp->applicationVersion(), QString::number(reader->countOfUnseenMessages())));

    qDebug() << tr("%1%2 launched.").arg(APP_ID, qApp->applicationName());
}

FormMain::~FormMain() {
    delete ui;
    reader->deleteLater();
}

void FormMain::createConnections() {
    connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showDialogAbout()));
    connect(ui->actionQuit, SIGNAL(triggered()), this, SLOT(quit()));
    connect(ui->actionImport, SIGNAL(triggered()), this, SLOT(importFeeds()));
    connect(ui->actionExport, SIGNAL(triggered()), this, SLOT(exportFeeds()));
    connect(ui->actionSettings, SIGNAL(triggered()), this, SLOT(showDialogSettings()));
    connect(ui->actionClearMessages, SIGNAL(triggered()), this, SLOT(deleteMessages()));
    connect(ui->actionRestoreMessages, SIGNAL(triggered()), this, SLOT(restoreMessages()));
    connect(ui->actionEmptyStorage, SIGNAL(triggered()), this, SLOT(trashMessages()));
    connect(ui->actionMarkAllRead, SIGNAL(triggered()), this, SLOT(markAllRead()));
    connect(ui->actionMarkAllUnread, SIGNAL(triggered()), this, SLOT(markAllUnread()));
    connect(ui->actionMarkRead, SIGNAL(triggered()), this, SLOT(markRead()));
    connect(ui->actionMarkUnread, SIGNAL(triggered()), this, SLOT(markUnread()));
    connect(ui->actionUpdateAllFeeds, SIGNAL(triggered()), this, SLOT(updateAllFeeds()));
    connect(ui->actionUpdateOneFeed, SIGNAL(triggered()), this, SLOT(updateFeed()));
    connect(ui->actionAddFeed, SIGNAL(triggered()), this, SLOT(addFeed()));
    connect(ui->actionEditFeed, SIGNAL(triggered()), this, SLOT(editItem()));
    connect(ui->actionDeleteFeed, SIGNAL(triggered()), this, SLOT(deleteFeed()));

    connect(ui->treeFeeds, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editItem()));

    connect(timer, SIGNAL(timeout()), this, SLOT(timerTick()));
    connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
    connect(txtSearch, SIGNAL(textChanged(QString)), this, SLOT(filterMessages()));
    connect(ui->tabMain, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));

    connect(this, SIGNAL(listNeedsRefresh()), this, SLOT(refreshList()));
    connect(this, SIGNAL(trayNeedsRefresh()), this, SLOT(refreshTrayIcon()));
    connect(tray, SIGNAL(trayHovered()), this, SLOT(refreshTrayTooltip()));

    connect(ui->treeFeeds, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(renameEditItemAction()));
    connect(ui->treeFeeds, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), txtSearch, SLOT(clear()));
    connect(ui->treeFeeds, SIGNAL(mousePressed(QMouseEvent*)), this, SLOT(contextMenuFeed(QMouseEvent*)));
    connect(ui->treeFeeds, SIGNAL(keyPressed(QKeyEvent*)), this, SLOT(shortcutFeeds(QKeyEvent*)));
    connect(ui->treeMessages, SIGNAL(itemMouseClicked(QTreeWidgetItem*,int)), this, SLOT(goToLink(QTreeWidgetItem*,int)));
    connect(ui->treeMessages, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(expandMessage(QTreeWidgetItem*,int)));
    connect(ui->treeMessages, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(displayMessage(QTreeWidgetItem*,QTreeWidgetItem*)));
    connect(ui->treeMessages, SIGNAL(keyPressed(QKeyEvent*)), this, SLOT(shortcutMessages(QKeyEvent*)));
}

void FormMain::closeTab(int index) {
    if (index) {
        delete ui->tabMain->widget(index);
    }
}

bool FormMain::isFeedSelected() {
    return (ui->treeFeeds->selectedItems().size() && !ui->treeFeeds->selectedItems().at(0)->childCount());
}

bool FormMain::isCategorySelected() {
    return (ui->treeFeeds->selectedItems().size() && ui->treeFeeds->selectedItems().at(0)->childCount());
}

void FormMain::shortcutFeeds(QKeyEvent *event) {
    if (event->key() == Qt::Key_Delete)
        deleteFeed();
}

void FormMain::shortcutMessages(QKeyEvent *event) {
    if (event->key() == Qt::Key_Delete) {
        QList<QTreeWidgetItem*> list = ui->treeMessages->selectedItems();
        for (int i = 0; i < list.size(); i++) {
            reader->getItemByLink(list.at(i)->toolTip(0))->setHidden(true);
            delete list.at(i);
        }
        emit listNeedsRefresh();
    }
}

void FormMain::contextMenuFeed(QMouseEvent *event) {
    renameEditItemAction();
    if (event->button() == Qt::RightButton) {
        if (ui->treeFeeds->itemAt(event->pos())) {
            QMenu menu(this);

            menu.addAction(ui->actionUpdateOneFeed);
            menu.addAction(ui->actionMarkRead);
            menu.addAction(ui->actionMarkUnread);
            menu.addSeparator();
            menu.addAction(ui->actionEditFeed);
            menu.addAction(ui->actionDeleteFeed);
            menu.exec(event->globalPos());
        }
        else {
            QMenu menu(this);

            menu.addAction(ui->actionUpdateAllFeeds);
            menu.addAction(ui->actionAddFeed);
            menu.addAction(ui->actionImport);
            menu.addAction(ui->actionExport);
            menu.exec(event->globalPos());
        }
    }
}

void FormMain::refreshList() {
    reader->updateColors(ui->treeFeeds);
    emit trayNeedsRefresh();
}

void FormMain::filterMessages() {
    QTreeWidgetItemIterator it(ui->treeMessages);
    while (*it) {
        if ((*it)->text(0).contains(txtSearch->text(), Qt::CaseInsensitive))
            (*it)->setHidden(false);
        else
            (*it)->setHidden(true);
        *it++;
    }
}

void FormMain::displayMessage(QTreeWidgetItem *current, QTreeWidgetItem *previous) {
    Q_UNUSED(previous)
    if (current) {
        if (reader->getItemByLink(current->toolTip(0)))
            reader->getItemByLink(current->toolTip(0))->updateRepresentation(ui->webMessages);
        current->setFont(0, QFont());
    }
    emit listNeedsRefresh();
}

void FormMain::expandMessage(QTreeWidgetItem *message, int column) {
    if (settings->value("useNewTab", true).toBool()) {
        if (settings->value("openWebsite", true).toBool()) {
            QWebView *view = new QWebView(this);
            ui->tabMain->addTab(view, message->text(0));
            view->load(QUrl(message->toolTip(0)));
        }
        else {
            QWebView *view = new QWebView(this);
            ui->tabMain->addTab(view, message->text(0));
            if (reader->getItemByLink(message->toolTip(0)))
                reader->getItemByLink(message->toolTip(0))->updateRepresentation(view);
        }
    }
    else {
        goToLink(message, column);
    }
}

void FormMain::goToLink(QTreeWidgetItem *message, int column) {
    if (column == RIGHT) {
        if (settings->value("rightClickbrowser", false).toBool()) {
            QDesktopServices::openUrl(message->toolTip(0));
        }
        return;
    }
    if (column == LEFT) return;
    if (settings->value("useBrowser", false).toBool() && QFile(settings->value("browser", "").toString()).exists()) {
        QProcess browser;
        browser.startDetached(settings->value("browser", "").toString(), QStringList() << message->toolTip(0));
    }
    else
        QDesktopServices::openUrl(message->toolTip(0));
}

void FormMain::dragEnterEvent(QDragEnterEvent * event) {
    if (event->mimeData()->hasFormat("text/plain"))
        event->acceptProposedAction();
}

void FormMain::dropEvent(QDropEvent *event) {
    addFeed(event->mimeData()->text());
}

void FormMain::deleteFeed() {

    if ((isCategorySelected() || isFeedSelected())) {
        QString key(ui->treeFeeds->selectedItems().at(0)->text(0));
        ui->treeMessages->clear();
        setMessage(tr("No message selected"));
        delete ui->treeFeeds->selectedItems().at(0);
        /*
        reader->updateRepresentation(ui->treeFeeds);
        if (ui->treeFeeds->selectedItems().size() > 0 && !ui->treeFeeds->selectedItems().at(0)->parent() &&
                !ui->treeFeeds->selectedItems().at(0)->childCount())
            delete  ui->treeFeeds->selectedItems().at(0);
        */
        if (isFeedSelected()) {
            reader->removeFeed(key);
        }
        else if (isCategorySelected()) {
            reader->removeCategory(key);
        }
    }
    emit trayNeedsRefresh();
}

void FormMain::importFeeds() {
    QString selected;
    QString fileName = QFileDialog::getOpenFileName(this, tr("Import file"), QDir::homePath(),
                                                    "OPML 1.0 (*.opml *.xml);;RSS Guard XML (*.rgx);;", &selected);
    if (!fileName.size()) return;
    QMessageBox msgBox;
    msgBox.setText(tr("Do you want to append imported feeds to existing ones or delete them? Use Yes option to append or No to delete"));
    msgBox.setWindowTitle(tr("Append or delete"));
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox.setDefaultButton(QMessageBox::Yes);
    int ret = msgBox.exec();
    bool append = false;
    if (ret == QMessageBox::Yes)
        append = true;
    if (selected == "OPML 1.0 (*.opml *.xml)")
        reader->loadOpml(append, fileName);
    else if (selected == "RSS Guard XML (*.rgx)")
        reader->loadXml(append, fileName);
    reader->updateRepresentation(ui->treeFeeds);
    emit trayNeedsRefresh();
}

void FormMain::exportFeeds() {
    QString selected;
    QString fileName = QFileDialog::getSaveFileName(this, tr("Export file"), QDir::homePath(),
                                                    "OPML 1.0 (*.opml *.xml);;RSS Guard XML (*.rgx);;", &selected);
    if (!fileName.size()) return;
    if (selected == "OPML 1.0 (*.opml *.xml)")
        reader->saveOpml(fileName);
    else if (selected == "RSS Guard XML (*.rgx)")
        reader->saveXml(fileName);
}

void FormMain::showDialogAbout() {
    FormAbout *aboutDialog = new FormAbout(":/text/text/COPYING", this);
    aboutDialog->show();
}

void FormMain::switchWindow() {
    if (isVisible())
        hide();
    else {
        setWindowState(Qt::WindowActive);
        show();
    }
}

void FormMain::setupApp() {

#ifdef Q_WS_MAC
    setUnifiedTitleAndToolBarOnMac(true);
#endif

    ui->treeFeeds->setStyleSheet("QTreeWidget:branch:!has-children { border-image: none; border: 0px transparent; }");

    qApp->setQuitOnLastWindowClosed(false);

    QString defaultPath = APP_PATH_BASE + QDir::separator() + APP_PATH_FEEDS;
    if (QFile(qApp->applicationDirPath() + QDir::separator() + APP_PATH_FEEDS).exists())
        reader = new RssReader(qApp->applicationDirPath() + QDir::separator() + APP_PATH_FEEDS);
    else
        reader = new RssReader(defaultPath);
    timer = new Timer(this);
    timer->setInterval(2000);

    bar = new QProgressBar(this);
    bar->hide();
    ui->statusBar->addWidget(bar);
    bar->setSizePolicy(QSizePolicy());

    statusText = new QLabel(this);
    statusText->hide();
    ui->statusBar->addWidget(statusText);

    txtSearch = new LineEdit(this, tr("Search"));

    spacerWidget = new QWidget(this);
    spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

    ui->toolBar->addWidget(spacerWidget);
    ui->toolBar->addWidget(txtSearch);
    txtSearch->setStyleSheet("margin-right: 5px;");
    txtSearch->setMinimumWidth(160);
    txtSearch->setMaximumWidth(160);
    spacerWidget->setVisible(true);
    txtSearch->setVisible(true);

    trayHasntNew = QIcon(":/graph/graphics/rssguard.png");
    trayFont.setBold(true);
    trayFont.setPointSize(42);
    trayPen = QPen(Qt::white);
    trayRectangle = QRect(10, 0, 108, 110);

    // TODO: Better size handling of column widths
    ui->treeFeeds->setColumnWidth(1, 60);
    ui->treeFeeds->setColumnWidth(2, 60);
}

void FormMain::refreshTrayIcon() {
    if (reader->countOfUnseenMessages()) {
        QPixmap icon = QPixmap(":/graph/graphics/rssguard-active.png");
        trayPainter.begin(&icon);
        trayPainter.setFont(trayFont);
        trayPainter.setPen(trayPen);
        trayPainter.drawText(trayRectangle, Qt::AlignVCenter | Qt::AlignCenter , QString::number(reader->countOfUnseenMessages()));
        trayPainter.end();
        // no tray on mac - only dock
#ifdef Q_OS_MAC
        qApp->setWindowIcon(icon);
#else
        tray->setIcon(icon);
#endif
    }
    else {
        // no tray on mac - only dock
#ifdef Q_OS_MAC
        qApp->setWindowIcon(trayHasntNew);
#else
        tray->setIcon(trayHasntNew);
#endif
    }
#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
    refreshTrayTooltip();
#endif
}

void FormMain::refreshTrayTooltip() {
    QStringList list;
    list << ":/graph/graphics/rssguard-small.png" << "RSS Guard" << tr("Unread messages: %1").arg(QString::number(reader->countOfUnseenMessages()));
#if defined(Q_WS_X11)
    if (settings->value("updateAutomatically", true).toBool())
        list << tr("Next update (minutes): %1").arg(timer->timeLeft());
#endif
    tray->setToolTip(list);
}


void FormMain::setupTray() {
    tray = new SystemTrayIcon(QIcon(":/graph/graphics/rssguard.png"), this);
    // Mac OS X hack here. It looks like it's better not to
    // show tray icon on mac because it's functionality duplicates
    // the Dock only - there is no additional stuff.
    // Also the "count of unread news" is almost unreadable in the tray
    // but it works perfectly in the dock.
#ifndef Q_OS_MAC
    tray->setToolTip("RSS Guard");
    if (!QSystemTrayIcon::isSystemTrayAvailable()) {
        QMessageBox::critical(0, "RSS Guard", tr("Your system doesn't support tray icon. RSS Guard will start in signle-window mode."));
        qWarning() << tr("Your system doesn't support tray icon. RSS Guard will start in single-window mode.");
        qApp->setQuitOnLastWindowClosed(true);
        return;
    }
    setupTrayMenu(tray);
    tray->show();
#endif
}

void FormMain::setupTrayMenu(QSystemTrayIcon *tray) {
    QMenu *menu = new QMenu(this);
    menu->addAction(ui->actionUpdateAllFeeds);
    menu->addAction(ui->actionMarkAllRead);
    menu->addSeparator();
    menu->addAction(ui->actionSettings);
    menu->addAction(ui->actionQuit);
    tray->setContextMenu(menu);
}

void FormMain::trayActivated(QSystemTrayIcon::ActivationReason r) {
#ifndef Q_WS_MAC
    switch (r) {
        case QSystemTrayIcon::Trigger:
            switchWindow();
            break;
        default:
            break;
    }
#else
    // thx to Petr Vanek
    Q_UNUSED(r);
    setWindowState(Qt::WindowActive);
    show();
#endif
}

void FormMain::quit() {
    tray->hide();

    if (settings->value("deleteReadOnExit", false).toBool())
        reader->hideMessages(true);

    saveSettings();
    if (!reader->saveXml(reader->getPath())) {
        QMessageBox::warning(this, tr("Feeds weren't saved"), tr("Feeds couldn't be save in local storage file, because file is probably read-only."));
        qWarning() << tr("Feeds couldn't be save in local storage file, because file is probably read-only.");
    }
    qDebug() << tr("%1%2 is quitting.").arg(APP_ID, qApp->applicationName());
    QApplication::quit();
}

void FormMain::setupSettings() {
    QString defaultPath = APP_PATH_BASE + QDir::separator() + APP_PATH_CONFIG;
    if (QFile(qApp->applicationDirPath() + QDir::separator() + APP_PATH_CONFIG).exists())
        settings = new QSettings(qApp->applicationDirPath() + QDir::separator() + APP_PATH_CONFIG, QSettings::IniFormat, this);
    else
        settings = new QSettings(defaultPath, QSettings::IniFormat, this);
    checkSettings(settings);
}

void FormMain::saveSettings() {
    settings->setValue(CONFIG_WINDOW_STATE, saveState());
    settings->setValue(CONFIG_WINDOW_GEOM, saveGeometry());

    settings->setValue("splitMainGeometry", ui->splitMain->saveGeometry());
    settings->setValue("splitMainState", ui->splitMain->saveState());

    settings->setValue("splitMessagesGeometry", ui->splitMessages->saveGeometry());
    settings->setValue("splitMessagesState", ui->splitMessages->saveState());

    settings->setValue("treeFeedsFirstColumn", ui->treeFeeds->columnWidth(0));

    checkSettings(settings);
}

void FormMain::loadSettings() {
    checkSettings(settings);
    if (settings->value("firstRun", true).toBool()) {
        QMessageBox msgBox;
        msgBox.setText(tr("Hello! Welcome in RSS Guard. RSS Guard is (very) tiny feed reader.\n\n") +
                       tr("If you want to get further information, then use Help menu item.\n\n") +
                       tr("You can change language of RSSG in Settings menu section.\n\n") +
                       tr("Remember that RSSG is open-source software, so you can get source code for it and use it under GNU GPLv3 licence only. For further information visit Help section too.\n\n\nCopyright ©  2011 Martin Rotter"));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setIconPixmap(QPixmap(":/graph/graphics/RssGuard.png"));
        msgBox.exec();
        settings->setValue("firstRun", false);
    }
    if (settings->value("updateAutomatically", true).toBool())
        timer->start(settings->value("updateInterval", 1800000).toInt());
    restoreState(settings->value(CONFIG_WINDOW_STATE).toByteArray());
    restoreGeometry(settings->value(CONFIG_WINDOW_GEOM).toByteArray());

    ui->splitMain->restoreGeometry(settings->value("splitMainGeometry").toByteArray());
    ui->splitMain->restoreState(settings->value("splitMainState").toByteArray());

    ui->splitMessages->restoreGeometry(settings->value("splitMessagesGeometry").toByteArray());
    ui->splitMessages->restoreState(settings->value("splitMessagesState").toByteArray());

    ui->treeFeeds->setColumnWidth(0, settings->value("treeFeedsFirstColumn").toInt());

    switchCounts();
}

void FormMain::expandTreeWidget(QTreeWidget *widget) {
    QTreeWidgetItemIterator it(widget);
    while (*it) (*it++)->setExpanded(true);
}

void FormMain::checkSettings(QSettings *settings) {
    settings->sync();
    if(settings->status() != QSettings::NoError) {
        QMessageBox::warning(NULL, "RSS Guard", tr("RSS Guard configuration initialization failed!!!\nCouldn't work with configuration file.\n\nFile: %1").arg(APP_PATH_CONFIG));
        qWarning() << tr("RSS Guard configuration initialization failed!!!\nCouldn't work with configuration file.\n\nFile: %1").arg(APP_PATH_CONFIG);
    }
}

void FormMain::setMessage(const QString &uri) {
    ui->webMessages->setHtml(FormMain::getHeader(uri));
}

void FormMain::addFeed(const QString &link) {
    FormEditFeed feedDialog(reader, this, link);
    RssFeed *feed = feedDialog.editFeed();

    reader->addFeed(feed);
    reader->updateRepresentation(ui->treeFeeds);
    ui->treeMessages->clear();
    emit listNeedsRefresh();
    setMessage(tr("No message selected"));
}

void FormMain::renameEditItemAction() {
    if (isFeedSelected()) {
        ui->actionMarkRead->setText(tr("Mark feed as read"));
        ui->actionMarkRead->setToolTip(tr("Mark this feed as read"));
        ui->actionMarkUnread->setText(tr("Mark feed as unread"));
        ui->actionMarkUnread->setToolTip(tr("Mark this feed as unread"));

        ui->actionUpdateOneFeed->setText(tr("Update feed"));
        ui->actionUpdateOneFeed->setToolTip(tr("Update this feed"));
        ui->actionEditFeed->setText(tr("Edit feed"));
        ui->actionDeleteFeed->setText(tr("Delete feed"));
        ui->actionEditFeed->setToolTip(tr("Edit this feed"));
        ui->actionDeleteFeed->setToolTip(tr("Delete this feed"));
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
        setMessage(tr("No message selected"));
    }
    else if (isCategorySelected()) {
        ui->actionMarkRead->setText(tr("Mark category as read"));
        ui->actionMarkRead->setToolTip(tr("Mark this category as read"));
        ui->actionMarkUnread->setText(tr("Mark category as unread"));
        ui->actionMarkUnread->setToolTip(tr("Mark this category as unread"));

        ui->actionUpdateOneFeed->setText(tr("Update category"));
        ui->actionUpdateOneFeed->setToolTip(tr("Update this category"));
        ui->actionEditFeed->setText(tr("Edit category"));
        ui->actionDeleteFeed->setText(tr("Delete category"));
        ui->actionEditFeed->setToolTip(tr("Edit this category"));
        ui->actionDeleteFeed->setToolTip(tr("Delete this category"));
        QList<RssFeed*> feeds = reader->getFeedsByCategory(ui->treeFeeds->selectedItems().at(0)->text(0));
        ui->treeMessages->clear();
        foreach (RssFeed *feed, feeds) {
            feed->updateRepresentation(ui->treeMessages, true);
        }
    }
}

void FormMain::editItem() {
    if (isFeedSelected()) {
        FormEditFeed feedDialog(reader, this);
        RssFeed *oldFeed = reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0));
        QString oldLink = oldFeed->getLink();
        QString oldEnc = oldFeed->getEncoding();
        RssFeed  *newFeed = feedDialog.editFeed(oldFeed);
        if (newFeed == NULL) return;
        QString newLink = newFeed->getLink();
        QString newEnc = newFeed->getEncoding();
        if (newLink != oldLink || oldEnc != newEnc) {
            QMessageBox::information(this, tr("Feed's link or encoding were changed"), tr("You have changed link or encoding in one of your feeds. All messages from this feed were permanently erased. Please update your feed to get new ones."));
            ui->treeMessages->clear();
        }
        reader->editFeed(oldFeed, newFeed);
        reader->updateRepresentation(ui->treeFeeds);
        emit listNeedsRefresh();
    }
    else if (isCategorySelected()) {
        FormEditCategory formCategory(ui->treeFeeds->selectedItems().at(0)->text(0) ,this);
        QString newName;
        if (formCategory.getText(&newName)) {
            reader->editCategory(ui->treeFeeds->selectedItems().at(0)->text(0), newName);
            reader->updateRepresentation(ui->treeFeeds);
        }
        emit listNeedsRefresh();
    }
}

void FormMain::markRead() {
    if (isFeedSelected()) {
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->markAllVisibleMessages(true);
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
        emit listNeedsRefresh();
    }
    else if (isCategorySelected())
        markCategoryRead();
}

void FormMain::markUnread() {
    if (isFeedSelected()) {
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->markAllVisibleMessages(false);
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
        emit listNeedsRefresh();
    }
    else if (isCategorySelected())
        markCategoryUnread();
}

void FormMain::markAllRead() {
    reader->markReader(true);
    if (isFeedSelected())
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
    emit listNeedsRefresh();
}

void FormMain::markAllUnread() {
    reader->markReader(false);
    if (isFeedSelected())
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
    emit listNeedsRefresh();
}

void FormMain::deleteMessages() {
    QMessageBox msgBox;
    msgBox.setText(tr("Do you want to delete read messages only?"));
    msgBox.setInformativeText(tr("If you want to delete just read messages, then use Yes as your answer. But if you want to dellete all (unread too) messages, then select No as your answer"));
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
    msgBox.setDefaultButton(QMessageBox::Yes);
    int result = msgBox.exec();
    if (result == QMessageBox::Yes) {
        reader->hideMessages(true);
        ui->treeMessages->clear();
        if (isFeedSelected())
            reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
        setMessage(tr("No message selected"));
    }
    else if (result == QMessageBox::No) {
        reader->hideMessages(false);
        ui->treeMessages->clear();
        setMessage(tr("No message selected"));
    }
    emit listNeedsRefresh();
}

void FormMain::restoreMessages() {
    QMessageBox msgBox;
    msgBox.setText(tr("Do you want to restore all deleted messages?"));
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox.setDefaultButton(QMessageBox::Yes);
    int result = msgBox.exec();
    if (result == QMessageBox::Yes)
        reader->unhideMessages();
    if (isFeedSelected())
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
    emit listNeedsRefresh();
}


void FormMain::trashMessages() {
    QMessageBox msgBox;
    msgBox.setText(tr("Do you want to clear local messages storage? If you will do this, then local configuration file will be cleaner and all messages will be downloaded again on next feed update."));
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox.setDefaultButton(QMessageBox::Yes);
    int result = msgBox.exec();
    if (result == QMessageBox::Yes) {
        reader->trashAllMessages();
        ui->treeMessages->clear();
        setMessage(tr("No message selected"));
    }
    emit listNeedsRefresh();
}

void FormMain::timerTick() {
    updateAllFeeds();
}

void FormMain::showDialogSettings() {
    QString lang = settings->value("currentLanguage", "English").toString();
    bool automat = settings->value("updateAutomatically", true).toBool();
    int interv = this->settings->value("updateInterval", 1800000).toInt();
    FormSettings form(settings, this);
    if (form.exec() == QDialog::Accepted) {
        if ((settings->value("updateAutomatically", true).toBool() == true) &&
                ((settings->value("updateInterval", 1800000).toInt() != interv) ||
                 (settings->value("updateAutomatically", true).toBool() == !automat))) {
            timer->start(settings->value("updateInterval", 1800000).toInt());
        }
        else if (settings->value("updateAutomatically", true).toBool() == false)
            timer->stop();
        switchCounts();
        if (lang != settings->value("currentLanguage", "English").toString())
            QMessageBox::information(this, tr("Language changed"), tr("Language of RSSG has changed. Please restart application to changes to take effect."));
    }
}

void FormMain::switchCounts() {
    ui->treeFeeds->setColumnHidden(1, !settings->value("unreadCounts", false).toBool());
    ui->treeFeeds->setColumnHidden(2, !settings->value("unreadCounts", false).toBool());
    ui->treeFeeds->setHeaderHidden(!settings->value("unreadCounts", false).toBool());
}

void FormMain::markCategoryRead() {
    if (isCategorySelected()) {
        QString categoryName = ui->treeFeeds->selectedItems().at(0)->text(0);
        QList<RssFeed*> listFeeds = reader->getFeedsByCategory(categoryName);
        foreach (RssFeed *feed, listFeeds) {
            feed->markAllVisibleMessages(true);
        }

        ui->treeMessages->clear();
        foreach (RssFeed *feed, listFeeds) {
            feed->updateRepresentation(ui->treeMessages, true);
        }
        emit listNeedsRefresh();
    }
}

void FormMain::markCategoryUnread() {
    if (isCategorySelected()) {
        QString categoryName = ui->treeFeeds->selectedItems().at(0)->text(0);
        QList<RssFeed*> listFeeds = reader->getFeedsByCategory(categoryName);
        foreach (RssFeed *feed, listFeeds) {
            feed->markAllVisibleMessages(false);
        }

        ui->treeMessages->clear();
        foreach (RssFeed *feed, listFeeds) {
            feed->updateRepresentation(ui->treeMessages, true);
        }
        emit listNeedsRefresh();
    }
}

void FormMain::updateFeed() {
    if (isFeedSelected()) {
        QNetworkReply::NetworkError result;
        Thread thr(reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0)), &result, settings->value("updateTimeout", DEF_TIMEOUT).toInt());
        thr.start();
        while (!thr.isFinished()) {
            qApp->processEvents();
        }
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
    }
    else
        updateCategory();
    emit listNeedsRefresh();
}

void FormMain::updateCategory() {
    if (isCategorySelected()) {
        QString categoryName = ui->treeFeeds->selectedItems().at(0)->text(0);
        QList<RssFeed*> listFeeds = reader->getFeedsByCategory(categoryName);

        bar->setVisible(true);
        bar->setValue(0);
        bar->setMaximum(listFeeds.size());

        statusText->setVisible(true);

        foreach (RssFeed *feed, listFeeds) {
            statusText->setText(tr("Updating feed: ") + feed->getTitle());
            QNetworkReply::NetworkError result;
            Thread thr(feed, &result, settings->value("updateTimeout", DEF_TIMEOUT).toInt());
            thr.start();
            while (!thr.isFinished()) {
                qApp->processEvents();
            }
            bar->setValue(bar->value() + 1);
        }
        bar->hide();
        statusText->hide();

        ui->treeMessages->clear();
        foreach (RssFeed *feed, listFeeds) {
            feed->updateRepresentation(ui->treeMessages, true);
        }

        int countOfSeen = reader->countOfUnseenMessages();
        if (countOfSeen > 0)
            tray->showMessage("RSS Guard", tr("RSS Guard updated feeds in category %1 and discovered, that there are unread messages.\nYou have %2 unread messages.").arg(categoryName, QString::number(countOfSeen)), QSystemTrayIcon::Information);
        else if (reader->getFeeds()->size())
            tray->showMessage("RSS Guard", tr("RSS Guard updated its feeds in category %1 and did not find any new unread messages.").arg(categoryName), QSystemTrayIcon::Information);
        emit listNeedsRefresh();
    }
}

void FormMain::updateAllFeeds() {
    bar->setVisible(true);
    bar->setValue(0);
    bar->setMaximum(reader->getFeeds()->size());

    statusText->setVisible(true);

    QMap<QString, QNetworkReply::NetworkError> problems;

    foreach (RssFeed *feed, *reader->getFeeds()) {
        statusText->setText(tr("Updating feed: ") + feed->getTitle());
        QNetworkReply::NetworkError result;
        Thread thr(feed, &result, settings->value("updateTimeout", DEF_TIMEOUT).toInt());
        thr.start();
        while (!thr.isFinished()) {
            qApp->processEvents();
        }
        bar->setValue(bar->value() + 1);
    }
    bar->hide();
    statusText->hide();
    if (isFeedSelected())
        reader->getFeedByName(ui->treeFeeds->selectedItems().at(0)->text(0))->updateRepresentation(ui->treeMessages);
    int countOfSeen = reader->countOfUnseenMessages();
    if (countOfSeen > 0)
        tray->showMessage("RSS Guard", tr("RSS Guard updated its feeds and discovered, that there are unread messages.\nYou have ") + QString::number(countOfSeen) + tr(" unread messages."), QSystemTrayIcon::Information);
    else if (reader->getFeeds()->size())
        tray->showMessage("RSS Guard", tr("RSS Guard updated its feeds and did not find any new unread messages."), QSystemTrayIcon::Information);
    emit listNeedsRefresh();
}

void FormMain::evaluateNetCodeError(QNetworkReply::NetworkError code) {
    if (code == QNetworkReply::NoError)
        return;

    QString answer = getNetCodeError(code);
    if (isVisible())
        QMessageBox::critical(this, tr("Error"), answer);
    else
        tray->showMessage(tr("Error"), answer, QSystemTrayIcon::Critical, 4000);
}

QString FormMain::getNetCodeError(QNetworkReply::NetworkError code) {
    switch (code) {
        case QNetworkReply::ProtocolFailure:
            // see RssFeed::parseFeed() setState(QNetworkReply::ProtocolFailure)
            return tr("Feed wasn't synchronized, because its source is not well-formed.");
        case QNetworkReply::HostNotFoundError:
        case QNetworkReply::RemoteHostClosedError:
        case QNetworkReply::ConnectionRefusedError:
            return tr("Feed wasn't synchronized, because RSSG was unable to reach target destination.");
        case QNetworkReply::TimeoutError:
        case QNetworkReply::ProxyTimeoutError:
            return tr("Connection to feed timed out.");
        case QNetworkReply::SslHandshakeFailedError:
            return tr("Feed updating failed. RSSG wasn't able to obtain SSL certificate.");
        default:
            /*
            QNetworkReply::OperationCanceledError
            QNetworkReply::TemporaryNetworkFailureError
            QNetworkReply::ProxyConnectionRefusedError
            QNetworkReply::ProxyConnectionClosedError
            QNetworkReply::ProxyNotFoundError
            QNetworkReply::ProxyAuthenticationRequiredError
            QNetworkReply::ContentAccessDenied
            QNetworkReply::ContentOperationNotPermittedError
            QNetworkReply::ContentNotFoundError
            QNetworkReply::AuthenticationRequiredError
            QNetworkReply::ContentReSendError
            QNetworkReply::ProtocolUnknownError
            QNetworkReply::ProtocolInvalidOperationError
            QNetworkReply::UnknownNetworkError -> this error occurs also when fetched file is not valid syndication format with supproted root xml element
            QNetworkReply::UnknownProxyError
            QNetworkReply::UnknownContentError
            */
            return tr("Connection to feed failed.");
    }
}


QString FormMain::getHeader(const QString &text) {
    QString string;
    string.push_back("<div style=\"-webkit-border-radius: 15px; text-align: center; border: solid 2px #EEEEEE;background-color: #f9f9f9;padding: 10px;margin: 4px 4px 0px 4px; float:both;\">");
    string.push_back(text);
    string.push_back("</div><br>");
    return string;
}
